package com.violet.db.util;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.violet.common.exception.BusinessException;
import com.violet.common.page.PageParam;
import com.violet.common.page.PageResult;
import com.violet.common.page.SortParam;
import com.violet.db.anno.QueryRule;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import static com.baomidou.mybatisplus.core.toolkit.StringUtils.UNDERLINE;

/**
 * 类说明: 分页工具类封装
 *
 * @author wqf
 * @date 2022/7/29 16:59
 */
@Slf4j
public class PageUtils<T> {

    private static final int IN_SIZE = 1000;

    /**
     * 分页参数封装
     *
     * @param pageParam 分页参数
     * @param <T>       查询对象
     * @return com.baomidou.mybatisplus.extension.plugins.pagination.Page<T>
     */
    public static <T> Page<T> getPage(PageParam pageParam) {
        return new Page<>(pageParam.getCurrent(), pageParam.getSize());
    }

    /**
     * 分页查询参数封装
     *
     * @param pageParam 分页条件
     * @param sortParam 排序条件
     * @param <T>       查询对象
     * @return com.baomidou.mybatisplus.extension.plugins.pagination.Page<T>
     */
    public static <T> Page<T> getPage(PageParam pageParam, SortParam sortParam) {
        Page<T> page = new Page<>(pageParam.getCurrent(), pageParam.getSize());
        List<OrderItem> order = getOrder(sortParam);
        if (order != null) {
            page.setOrders(getOrder(sortParam));
        }
        return page;
    }

    public static List<OrderItem> getOrder(SortParam sortParam) {
        if (sortParam == null || StrUtil.isBlank(sortParam.getSort())) {
            return null;
        }
        String sortStr = sortParam.getSort();
        String[] sorts = sortStr.split(",");
        if (sorts.length == 0) {
            throw new BusinessException("排序参数错误");
        }
        List<OrderItem> orderItems = new ArrayList<>();
        for (String sort : sorts) {
            OrderItem orderItem = new OrderItem();
            int lastIndex = sort.lastIndexOf(UNDERLINE);
            String field = sort.substring(0, lastIndex);
            //SQL注入检查
            field = SqlFilter.sqlInject(field);
            String sortType = sort.substring(lastIndex + 1);
            orderItem.setColumn(field);
            if (QueryConstant.DESC.equalsIgnoreCase(sortType)) {
                orderItem.setAsc(false);
            } else if (QueryConstant.ASC.equalsIgnoreCase(sortType)) {
                orderItem.setAsc(true);
            } else {
                log.info("=============排序条件错误=============");
                throw new IllegalArgumentException();
            }
            orderItems.add(orderItem);
        }
        return orderItems;
    }

    /**
     * 方法描述: 将mybatis-plus分页查询返回实体转化为自定义封装分页结果实体
     *
     * @param page 分页查询结果
     * @return com.violet.common.entity.page.PageResult<T>
     * @author wqf
     * @date 2023/6/14 9:20
     */
    public static <T> PageResult<T> convertPageResult(Page<T> page) {
        PageResult<T> pageResult = new PageResult<>();
        pageResult.setTotalCount(page.getTotal());
        pageResult.setCurrent(page.getCurrent());
        pageResult.setSize(page.getSize());
        pageResult.setTotalPage(page.getPages());
        pageResult.setRecords(page.getRecords());
        return pageResult;
    }


    public QueryWrapper<T> buildQueryWrapper(Object condition) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
        try {
            Field[] fields = condition.getClass().getDeclaredFields();
            //字段条件组装
            for (Field field : fields) {
                if (conditionAssembly(queryWrapper, condition, field)) {
                    continue;
                }
                field.setAccessible(false);
            }
            return queryWrapper;
        } catch (Exception e) {
            log.error("MybatisPlusPageUtils buildqueryWrapper queryWrapper={},error={}", queryWrapper, e.getMessage());
        }
        return queryWrapper;
    }

    /**
     * 方法描述: 查询条件组装
     *
     * @param queryWrapper 查询条件
     * @param condition    查询条件实体
     * @param field        字段名称
     * @return boolean
     * @author wqf
     * @date 2022/7/29 17:53
     */
    private boolean conditionAssembly(QueryWrapper<T> queryWrapper, Object condition, Field field) throws IllegalAccessException {
        QueryRule annotation = field.getAnnotation(QueryRule.class);
        if (annotation == null) {
            return true;
        }
        field.setAccessible(true);
        String objValue = String.valueOf(field.get(condition));
        if ("null".equals(objValue) || StrUtil.isBlank(objValue)) {
            return true;
        }
        String fieldValue = annotation.value();
        handlerValues(queryWrapper, annotation, field.get(condition), fieldValue);
        return false;
    }

    /**
     * 方法描述: 处理查询条件
     *
     * @param queryWrapper 条件构造器
     * @param annotation   排序条件
     * @param objValue     排序条件
     * @param fieldValue   排序条件
     * @author wqf
     * @date 2022/7/29 17:51
     */
    private void handlerValues(QueryWrapper<T> queryWrapper, QueryRule annotation, Object objValue, String fieldValue) {
        switch (annotation.queryCriteria()) {
            case EQ -> queryWrapper.eq(fieldValue, objValue);
            case LIKE -> queryWrapper.like(fieldValue, objValue);
            case LIKE_LEFT -> queryWrapper.likeLeft(fieldValue, objValue);
            case LIKE_RIGHT -> queryWrapper.likeRight(fieldValue, objValue);
            case GT -> queryWrapper.gt(fieldValue, objValue);
            case LT -> queryWrapper.lt(fieldValue, objValue);
            case GTE -> queryWrapper.ge(fieldValue, objValue);
            case LTE -> queryWrapper.le(fieldValue, objValue);
            case NE -> queryWrapper.ne(fieldValue, objValue);
            case IS_NULL -> queryWrapper.isNull(fieldValue);
            case IS_NOT_NULL -> queryWrapper.isNotNull(fieldValue);
            case IN -> parseIn((List<?>) objValue, fieldValue, queryWrapper);
            case NOT_IN -> parseNotIn((List<?>) objValue, fieldValue, queryWrapper);
            default -> {
            }
        }
    }


    public static <T> void parseIn(List<?> dataList, String fieldValue, QueryWrapper<T> queryWrapper) {
        if (dataList.size() < IN_SIZE) {
            StringBuilder sb = new StringBuilder(dataList.size() * 3);
            queryWrapper.inSql(fieldValue, parameterSplicing(dataList, sb));
        }
        List<String> subSqlStr = batchParameterSplicing(dataList, new ArrayList<>(dataList.size() / IN_SIZE + 1));
        for (int i = 0; i < subSqlStr.size(); i++) {
            String sql = subSqlStr.get(i);
            if (i == 0) {
                queryWrapper.inSql(fieldValue, sql);
            } else {
                queryWrapper.or(qw -> qw.inSql(fieldValue, sql));
            }
        }
    }

    public static <T> void parseNotIn(List<?> dataList, String fieldValue, QueryWrapper<T> queryWrapper) {
        if (dataList.size() < IN_SIZE) {
            StringBuilder sb = new StringBuilder(dataList.size() * 3);
            queryWrapper.notInSql(fieldValue, parameterSplicing(dataList, sb));
        }
        List<String> subSqlStr = batchParameterSplicing(dataList, new ArrayList<>(dataList.size() / IN_SIZE + 1));
        for (int i = 0; i < subSqlStr.size(); i++) {
            String sql = subSqlStr.get(i);
            if (i == 0) {
                queryWrapper.notInSql(fieldValue, sql);
            } else {
                queryWrapper.or(qw -> qw.notInSql(fieldValue, sql));
            }
        }
    }

    /**
     * 方法描述: 参数集合分批拼接成sql in内容
     *
     * @param dataList  参数集合
     * @param subSqlStr StringBuilder
     * @return void
     * @author wqf
     * @date 2022/8/1 9:02
     */
    private static List<String> batchParameterSplicing(List<?> dataList, List<String> subSqlStr) {
        List<? extends List<?>> suListArr = ListUtil.split(dataList, IN_SIZE - 1);
        for (List<?> list : suListArr) {
            StringBuilder sb = new StringBuilder(IN_SIZE);
            subSqlStr.add(parameterSplicing(list, sb));
        }
        return subSqlStr;
    }

    /**
     * 方法描述: 参数集合拼接成sql in内容
     *
     * @param list 参数集合
     * @param sb   StringBuilder
     * @return java.lang.String
     * @author wqf
     * @date 2022/8/1 8:54
     */
    private static String parameterSplicing(List<?> list, StringBuilder sb) {
        for (int i = 0; i < list.size(); i++) {
            sb.append("'").append(list.get(i)).append("'");
            if (i != list.size() - 1) {
                sb.append(",");
            }
        }
        return sb.toString();
    }

}